// wip work in progress当前正在工作中的
/**
 * 将vdom处理成dom并更新页面
 */
import {
  updateFragmentComponent,
  updateFunctionComponent,
  updateHostComponent,
} from "./ReactFiberReconciler";
import { schedulerCallback, shouldYield } from "./scheduler";
import { isFn, isStr, Placement, Update, updateNode } from "./utils";

let wipRoot = null;
// 下一个fiber节点
let nextUnitOfwork = null;
export function scheduleUpdateOnFiber(fiber) {
  fiber.alternate = { ...fiber }
  wipRoot = fiber;
  nextUnitOfwork = fiber;
  schedulerCallback(workLoop)
}

function performUnitOfWork(wip) {
  // 1. 更新wip
  const { type } = wip;
  if (isStr(type)) {
    updateHostComponent(wip);
  } else if (isFn(type)) {
    updateFunctionComponent(wip);
  } else {
    updateFragmentComponent(wip);
  }
  // todo
  // 2. 返回下一个要更新的任务 深度优先遍历
  if (wip.child) {
    return wip.child;
  }
  let next = wip;

  while (next) {
    if (next.sibling) {
      return next.sibling;
    }
    next = next.return;
  }
  return null;
}

function workLoop() {
  while (nextUnitOfwork && !shouldYield()) {
    nextUnitOfwork = performUnitOfWork(nextUnitOfwork);
  }

  if (!nextUnitOfwork && wipRoot) {
    commitRoot();
  }
}

// requestIdleCallback(workLoop);

function commitRoot() {

  isFn(wipRoot.type) ? commitWorker(wipRoot) : commitWorker(wipRoot.child);
  wipRoot = null;
}
function invokeHooks(wip) {
  const { updateQueueOfLayout, upDateQueueOfEffect } = wip;
  for (let i = 0; i < updateQueueOfLayout.length; i++) {
    const effect = updateQueueOfLayout[i]
    effect.create();
  }
  for (let i = 0; i < upDateQueueOfEffect.length; i++) {
    const effect = upDateQueueOfEffect[i]
    schedulerCallback(() => {
      effect.create();
    })
  }
}

function commitWorker(wip) {
  if (!wip) return;

  // 1。提交自己
  const { type, flags, stateNode } = wip;
  // fiber可能没有dom节点，比如函数组件类组件
  let parentNode = getParentNode(wip.return); //wip.return.stateNode; // 父dom节点

  if (flags & Placement && stateNode) {
    let hasSiblingNode = foundSiblingNode(wip, parentNode);
    if (hasSiblingNode) {
      parentNode.insertBefore(stateNode, hasSiblingNode);
    } else {
      parentNode.appendChild(wip.stateNode);
    }
  }
  if (flags & Update && stateNode) {
    updateNode(stateNode, wip.alternate.props, wip.props);
  }

  if (wip.deletions) {
    commitDeletions(wip.deletions, stateNode || parentNode)
    wip.deletions = null
  }

  if (isFn(type)) {
    invokeHooks(wip)
  }
  // 2、 子节点
  commitWorker(wip.child);
  // 3.兄弟
  commitWorker(wip.sibling);
}

function commitDeletions(deletions, parentNode) {
  for (let i = 0; i < deletions.length; i++) {
    const element = deletions[i];
    parentNode.removeChild(getStateNode(element))
  }
}
function getStateNode(fiber) {
  let lem = fiber
  while (!lem.stateNode) {
    lem = lem.child
  }
  return lem.stateNode
}

function getParentNode(fiber) {
  while (fiber) {
    if (fiber.stateNode) {
      return fiber.stateNode;
    }
    fiber = fiber.return;
  }
}

function foundSiblingNode(fiber, parentNode) {
  let siblingHasNode = fiber.sibling;
  let node = null;
  while (siblingHasNode) {
    node = siblingHasNode.stateNode;
    if (node && parentNode.contains(node)) {
      return node;
    }
    siblingHasNode = siblingHasNode.sibling;
  }

  return null;
}
